package com.soul.doc.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.soul.common.bean.comm.BasePo;
import com.soul.common.bean.vo.BaseDataVo;
import com.soul.common.constant.CacheConstants;
import com.soul.common.exception.BaseException;
import com.soul.common.service.BaseDataService;
import com.soul.common.utils.ListUtil;
import com.soul.common.utils.RedisCache;
import com.soul.doc.bean.dto.CollectionDto;
import com.soul.doc.bean.dto.MusicAddDto;
import com.soul.doc.bean.dto.MusicSearchDto;
import com.soul.doc.bean.dto.MusicUpdateDto;
import com.soul.doc.bean.po.HistoryPo;
import com.soul.doc.bean.po.LoveMusicPo;
import com.soul.doc.bean.po.MusicPo;
import com.soul.doc.bean.vo.MusicVo;
import com.soul.doc.bean.vo.SingerVo;
import com.soul.doc.mapper.MusicMapper;
import com.soul.doc.service.HistoryService;
import com.soul.doc.service.LoveMusicService;
import com.soul.doc.service.MusicService;
import com.soul.common.service.BaseService;
import com.soul.doc.service.SingerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author sws
 * @since 2023-11-19 11:08:12
 */
@Service
public class MusicServiceImpl extends BaseService<MusicMapper, MusicPo> implements MusicService {

    @Autowired
    private SingerService singerService;
    @Autowired
    private BaseDataService baseDataService;

    @Autowired
    private RedisCache redisCache;
    @Autowired
    private LoveMusicService loveMusicService;
    @Autowired
    private HistoryService historyService;
    @Override
    public IPage<MusicVo> queryMusicList(Integer page, Integer size, MusicSearchDto searchDto){
        QueryWrapper<MusicPo> query = Wrappers.query(new MusicPo());
//        LambdaQueryWrapper<MusicPo> wrapper = this.lambadaQueryWrapper();
        long userId = StpUtil.isLogin() ? StpUtil.getLoginIdAsLong() : 100L;
        boolean isDay = false;
        String code = null;
        if (ObjectUtil.isNotEmpty(searchDto)){

            if (ObjectUtil.isNotEmpty(searchDto.getKeyword())){
                // 关键词
                List<Long> singerIds = this.singerService.getSingerIdsByKeyWord(searchDto.getKeyword());
                searchDto.setSingerIds(singerIds);
            }
            if (ObjectUtil.equals(searchDto.getSortType(),"day")){
                // 今日推荐
                String today= DateUtil.today();
                code = CacheConstants.DAY_MUSIC_CODE_KEY + today + ":" + userId;
                List<MusicVo> cacheList = redisCache.getCacheObject(code);
                if (ObjectUtil.isNotEmpty(cacheList)){
                    IPage<MusicVo> convert = new Page<>(page, size);
                    return convert.setRecords(cacheList);
                }else {
                    isDay = true;
                }
            }
            query.orderByAsc(ObjectUtil.equals(searchDto.getSortType(),"day")," rand()");
            LambdaQueryWrapper<MusicPo> wrapper = query.lambda();
            wrapper.like(ObjectUtil.isNotEmpty(searchDto.getMusicName()),MusicPo::getMusicName,searchDto.getMusicName())
                    .eq(ObjectUtil.isNotEmpty(searchDto.getSingerId()),MusicPo::getSingerId,searchDto.getSingerId())
                    .or(ObjectUtil.isNotEmpty(searchDto.getKeyword()))
                    .like(ObjectUtil.isNotEmpty(searchDto.getKeyword()),MusicPo::getMusicName,searchDto.getKeyword())
                    .or(ObjectUtil.isNotEmpty(searchDto.getSingerIds()))
                    .in(ObjectUtil.isNotEmpty(searchDto.getSingerIds()),MusicPo::getSingerId,searchDto.getSingerIds())
                    .orderByDesc(ObjectUtil.equal(searchDto.getSortType(),"creatTimeDesc"),BasePo::getCreateTime)
                    .orderByDesc(ObjectUtil.equals(searchDto.getSortType(),"hot"),MusicPo::getCollectNum)
                    .orderByAsc(BasePo::getSort);

        }
        Page<MusicPo> userPoPage = this.page(new Page<>(page, size), query);
        List<MusicPo> records = userPoPage.getRecords();
        if (ObjectUtil.isEmpty(records)){
            return new Page<>();
        }
        List<Long> singerIds = ListUtil.toValueList(records, MusicPo::getSingerId);
        List<SingerVo> singerVos = singerService.getSingerVosByIds(singerIds);
        Map<Long, SingerVo> singerVoMap = ListUtil.listToMap(singerVos, SingerVo::getId);
        BaseDataVo baseDataVo = baseDataService.loadBaseData(records, (t, bd) -> {
            bd.addFileId(t.getMusicFileId(), t.getPicFileId());
        });
        IPage<MusicVo> convert = userPoPage.convert(t->this.toDataVo(t,baseDataVo));
        convert.getRecords().forEach(t->t.setSingerVo(singerVoMap.get(t.getSingerId())));
        setIsLoveByUser(convert.getRecords());
        if (isDay){
            // 缓存今日推荐
            List<MusicVo> recordsDay = convert.getRecords();
            // 明天五点,每天五点更新今日推荐
            Date tomorrow = DateUtil.offsetHour(DateUtil.beginOfDay(DateUtil.tomorrow()), 5);;
            // 过期时间,单位秒
            long between = DateUtil.between(DateUtil.date(), tomorrow, DateUnit.SECOND);
            redisCache.setCacheObject(code,recordsDay,between,CacheConstants.DAY_MUSIC_UNIT);
        }
        return convert;
    }

    @Override
    public void addMusic(MusicAddDto addDto) {
        MusicPo musicPo = BeanUtil.copyProperties(addDto, MusicPo.class);
        musicPo.setStatus(1);
        musicPo.setType("free");
        Long maxSort = this.getMaxSort();
        musicPo.setSort(maxSort);
        this.save(musicPo);
    }

    @Override
    public boolean addLove(CollectionDto collectionDto) {
        boolean b = loveMusicService.addLoveMusic(collectionDto);
        if (b){
            // 歌曲收藏数+1
            this.addCollectNum(collectionDto.getMusicId(),collectionDto.getType());
        }
        return b;
    }

    @Override
    public void addHistory(CollectionDto collectionDto) {
        historyService.addHistory(collectionDto);
    }

    private MusicVo toDataVo(MusicPo po){
        BaseDataVo baseDataVo = new BaseDataVo();
        baseDataVo.addFileId(po.getMusicFileId(),po.getPicFileId());
        baseDataService.loadBaseData(baseDataVo);
        MusicVo dataVo = this.toDataVo(po, baseDataVo);
        SingerVo singer = singerService.getSinger(po.getSingerId());
        dataVo.setSingerVo(singer);
        setIsLoveByUser(dataVo);
        return dataVo;
    }
    private MusicVo toDataVo(MusicPo po,BaseDataVo baseDataVo){
        MusicVo musicVo = BeanUtil.copyProperties(po, MusicVo.class);
        musicVo.setMusicFile(baseDataVo.getFileVo(musicVo.getMusicFileId()));
        musicVo.setPicFile(baseDataVo.getFileVo(musicVo.getPicFileId()));
        if (musicVo.getPicFile()!= null){
            musicVo.setPicUrl(musicVo.getPicFile().getUrl());
        }
        return musicVo;
    }

    @Override
    public synchronized void addPlayNum(Long musicId){
        MusicPo musicPo = this.getById(musicId);
        if (ObjectUtil.isEmpty(musicPo)){
            throw new BaseException("歌曲不存在！");
        }
        Long playNum = Optional.of(musicPo.getPlayNum()).orElse(0L) + 1;
        this.lambdaUpdate().set(MusicPo::getPlayNum,playNum).eq(MusicPo::getId,musicId).update();
        // 如果登录状态，保存一次历史记录
        if (StpUtil.isLogin()){
            CollectionDto collectionDto = new CollectionDto();
            collectionDto.setMusicId(musicId);
            this.historyService.addHistory(collectionDto);
        }
    }
    @Override
    public synchronized void addCollectNum(Long musicId,String type){
        MusicPo musicPo = this.getById(musicId);
        if (ObjectUtil.isEmpty(musicPo)){
            throw new BaseException("歌曲不存在！");
        }
        Long collectNum = Optional.of(musicPo.getCollectNum()).orElse(0L);
        if (ObjectUtil.equals(type,"remove")){
            collectNum = collectNum > 0 ? collectNum - 1 : 0;
        }else {
            collectNum++;
        }
        this.lambdaUpdate().set(MusicPo::getCollectNum,collectNum).eq(MusicPo::getId,musicId).update();
    }

    @Override
    public List<MusicVo> queryMusicByIds(Collection<Long> musicIds){
        if (ObjectUtil.isEmpty(musicIds)){
            return new ArrayList<>();
        }
        List<MusicPo> musicPos = this.listByIds(musicIds);
        BaseDataVo baseDataVo = baseDataService.loadBaseData(musicPos, (t, bd) -> {
            bd.addFileId(t.getMusicFileId(), t.getPicFileId());
        });
        List<MusicVo> musicVos = ListUtil.toValueList(musicPos, t -> this.toDataVo(t, baseDataVo));
        List<Long> singerIds = ListUtil.toValueList(musicPos, MusicPo::getSingerId);
        List<SingerVo> singerVos = singerService.getSingerVosByIds(singerIds);
        Map<Long, SingerVo> singerVoMap = ListUtil.listToMap(singerVos, SingerVo::getId);
        if (ObjectUtil.isNotEmpty(musicVos)){
            List<Long> loveMusicIds = loveMusicService.getLoveMusicIds();
            musicVos.forEach(m-> {
                if (ObjectUtil.isNotEmpty(loveMusicIds) && loveMusicIds.contains(m.getId())){
                    m.setIsLove(1);
                }
                m.setSingerVo(singerVoMap.get(m.getSingerId()));
            });
        }

        return musicVos;
    }

    @Override
    public List<MusicVo> queryLoveMusic(){
        List<MusicVo> retList = new ArrayList<>();
        List<LoveMusicPo> loveMusic = this.loveMusicService.getLoveMusic();
        if (ObjectUtil.isEmpty(loveMusic)){
            return new ArrayList<>();
        }
        List<Long> musicIds = ListUtil.toValueList(loveMusic, LoveMusicPo::getMusicId);
        List<MusicVo> musicVos = queryMusicByIds(musicIds);
        if (ObjectUtil.isNotEmpty(musicVos)){
            Map<Long, MusicVo> toMap = ListUtil.listToMap(musicVos, MusicVo::getId);
            loveMusic.forEach(t->{
                MusicVo musicVo = toMap.get(t.getMusicId());
                if (ObjectUtil.isNotEmpty(musicVo)){
                    retList.add(musicVo);
                }
            });
        }
        return retList;
    }

    @Override
    public MusicVo getMusicInfoById(Long id){
        MusicPo musicPo = this.getById(id);
        if (ObjectUtil.isEmpty(musicPo)){
            throw new BaseException("歌曲不存在！");
        }
        return this.toDataVo(musicPo);
    }

    public void setIsLoveByUser(List<MusicVo> musicVos){
        if (StpUtil.isLogin()){
            if (ObjectUtil.isNotEmpty(musicVos)){
                List<Long> loveMusicIds = loveMusicService.getLoveMusicIds();
                musicVos.forEach(m->{
                    setIsLoveByUser(m,loveMusicIds);
                });
            }
        }
    }
    public void setIsLoveByUser(MusicVo musicVo,List<Long> loveIds){
        if (StpUtil.isLogin()){
            if (ObjectUtil.isNotEmpty(musicVo) && ObjectUtil.isNotEmpty(loveIds) && loveIds.contains(musicVo.getId())){
                musicVo.setIsLove(1);
            }
        }
    }
    public void setIsLoveByUser(MusicVo musicVo){
        if (StpUtil.isLogin()){
            List<Long> loveMusicIds = loveMusicService.getLoveMusicIds();
            setIsLoveByUser(musicVo,loveMusicIds);
        }
    }

    @Override
    public List<MusicVo> getMusicHistory(Integer type){
        // 判断是否展开,默认 显示10首
        int pageSize = 10;
        if (type == 1){
            // 最多展示100首
            pageSize = 100;
        }
        List<HistoryPo> history = historyService.getHistory(pageSize);
        if (ObjectUtil.isEmpty(history)){
            return new ArrayList<>();
        }
        // 查询歌曲
        List<Long> musicIds = ListUtil.toValueList(history, HistoryPo::getMusicId);
        List<MusicVo> musicVos = this.queryMusicByIds(musicIds);
        Map<Long, HistoryPo> historyPoMap = ListUtil.listToMap(history, HistoryPo::getMusicId);
        musicVos.forEach(m->{
            HistoryPo historyPo = historyPoMap.get(m.getId());
            if (ObjectUtil.isEmpty(historyPo)){
                m.setPlayUserNum(0L);
            }else {
                m.setPlayUserNum(historyPo.getMusicCount());
            }
        });
        return musicVos;
    }

    @Override
    public void updateMusic(MusicUpdateDto updateDto){
        Long id = updateDto.getId();
        MusicPo musicPo = this.getById(id);
        if (ObjectUtil.isEmpty(musicPo)) {
            throw new BaseException("数据不存在！");
        }
        BeanUtil.copyProperties(updateDto,musicPo);
        this.updateById(musicPo);
    }
}
